feat: add read-first Week Ahead overview (Closes #1216)
This commit is contained in:
1 parent
45e2798d37
commit
42e97b4a79
6 files changed
+121
-20
No files matched your search
@@ -62,6 +62,26 @@ def test_release_artifact_plans_seven_touch_safe_mobile_dates(
|
||||
page.wait_for_timeout(100)
|
||||
|
||||
assert not page_errors, f"Week Ahead launch raised: {page_errors}"
|
||||
expect(page.locator("#plan-today-title")).to_have_text("Week Ahead")
|
||||
overview = page.locator("#week-review")
|
||||
expect(overview).to_be_visible()
|
||||
cards = page.locator("#week-review-days .week-review-day")
|
||||
expect(cards).to_have_count(7)
|
||||
expect(cards.first).to_contain_text("Next up")
|
||||
expect(cards.first).to_contain_text("Ship mobile capture")
|
||||
expect(page.locator("#week-review-status")).to_have_text(
|
||||
"Week Ahead overview · no changes made."
|
||||
)
|
||||
expect(page.locator("#confirm-week-plan")).to_be_hidden()
|
||||
edit_week = page.locator("#edit-week-plan")
|
||||
expect(edit_week).to_be_visible()
|
||||
assert saved == [], "opening and inspecting Week Ahead must not write"
|
||||
for control in (cards.first.locator("[data-week-edit-day]"), edit_week):
|
||||
bounds = control.bounding_box()
|
||||
assert bounds and bounds["height"] >= 44
|
||||
assert page.evaluate("document.documentElement.scrollWidth <= window.innerWidth")
|
||||
edit_week.click()
|
||||
expect(overview).to_be_hidden()
|
||||
expect(page.locator("#plan-today-title")).to_have_text("Plan Week Ahead")
|
||||
dates = page.locator("#week-plan-dates button")
|
||||
expect(dates).to_have_count(7)
|
||||
@@ -243,6 +263,7 @@ def test_release_artifact_reconciles_only_the_week_day_changed_on_both_devices(
|
||||
page.wait_for_url(origin + "/", wait_until="networkidle")
|
||||
page.locator('[data-mobile-task="queues"]').click()
|
||||
page.locator('[data-mobile-queue="week"]').click()
|
||||
page.locator("#edit-week-plan").click()
|
||||
page.locator("#plan-today-available").fill("60")
|
||||
page.locator("#save-today-plan").click()
|
||||
page.wait_for_function("() => document.querySelector('#mobile-week-summary').textContent.includes('Conflict')")
|
||||
|
||||
@@ -179,15 +179,18 @@ Object.defineProperty(root,'innerHTML',{set(value){this.value=value;this.buttons
|
||||
root.querySelectorAll=()=>root.buttons||[];
|
||||
root.querySelector=selector=>(root.buttons||[]).find(button=>selector.includes(button.dataset.weekPlanDate))||null;
|
||||
elements.set('#week-plan-dates',root);
|
||||
for(const selector of ['#mobile-week-summary','#my-work-action-status','#week-plan-progress','#save-today-plan']) elements.set(selector,makeElement());
|
||||
for(const selector of ['#mobile-week-summary','#my-work-action-status','#week-plan-progress','#save-today-plan',
|
||||
'#week-review','#week-review-days','#week-review-duplicates','#confirm-week-plan','#week-review-status','#edit-week-plan']) elements.set(selector,makeElement());
|
||||
let opened=0,staged=[];
|
||||
const controller={dates:()=>dates.map((date,index)=>({date,label:'Day '+(index+1)})),day:date=>({plan_date:date,ids:[]}),
|
||||
pass:date=>{const index=dates.indexOf(date);return {position:index+1,total:7,planned:staged.length,next_date:dates[index+1]||null,last:index===6};},
|
||||
load:async()=>({}),summary:()=> 'Nothing planned',stageDay:(date,plan)=>{staged.push({date,plan});return true;},flush:async()=>({})};
|
||||
load:async()=>({}),summary:()=> 'Nothing planned',review:()=>({days:dates.map(date=>({plan_date:date,label:date,ids:[],capacity_minutes:null,estimates:{},planned_minutes:0,overloaded:false})),duplicates:[],blockers:[],can_confirm:true}),pending:()=>false,
|
||||
stageDay:(date,plan)=>{staged.push({date,plan});return true;},flush:async()=>({})};
|
||||
const workflow=createWorkflow({controller,qs:selector=>elements.get(selector),getLogin:()=> 'timmy',
|
||||
openPlanner:()=>{opened+=1;},escapeHtml:value=>value,escapeAttribute:value=>value,
|
||||
todayWork:{replace:()=>{},replacePlanning:()=>{}},refresh:()=>{},warm:()=>{}});
|
||||
await workflow.open({disabled:false});
|
||||
workflow.editWeek();
|
||||
workflow.save({ids:['issue:r:1:'],capacity_minutes:60,estimates:{'issue:r:1:':30}});
|
||||
const continued=workflow.advance();
|
||||
console.log(JSON.stringify({continued,selected:workflow.selectedDate(),opened,staged,
|
||||
@@ -196,12 +199,67 @@ console.log(JSON.stringify({continued,selected:workflow.selectedDate(),opened,st
|
||||
|
||||
assert result["continued"] is True
|
||||
assert result["selected"] == "2026-08-22"
|
||||
assert result["opened"] == 3
|
||||
assert result["opened"] == 4
|
||||
assert result["staged"][0]["date"] == "2026-08-21"
|
||||
assert result["progress"] == "Day 2 of 7 · 1 planned"
|
||||
assert result["label"] == "Save & next"
|
||||
|
||||
|
||||
def test_week_workflow_opens_a_read_only_overview_with_next_up_work():
|
||||
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:'',addEventListener:()=>{},focus:()=>{},
|
||||
querySelectorAll:()=>[],querySelector:()=>null,scrollIntoView:()=>{}});
|
||||
const dateRoot=makeElement();
|
||||
Object.defineProperty(dateRoot,'innerHTML',{set(value){this.value=value;this.buttons=[];},get(){return this.value||'';}});
|
||||
elements.set('#week-plan-dates',dateRoot);
|
||||
const reviewDays=makeElement();
|
||||
Object.defineProperty(reviewDays,'innerHTML',{set(value){this.value=value;},get(){return this.value||'';}});
|
||||
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',
|
||||
'#edit-week-plan']) if(!elements.has(selector))elements.set(selector,makeElement());
|
||||
let writes=0,opened=0,reviewMode=false;
|
||||
const review={days:dates.map((date,index)=>({plan_date:date,label:'Day '+(index+1),
|
||||
ids:index===2?['issue:stackchain/dashboard:42:']:[],capacity_minutes:60,
|
||||
estimates:index===2?{'issue:stackchain/dashboard:42:':30}:{},planned_minutes:index===2?30:0,overloaded:false})),
|
||||
duplicates:[],blockers:[],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()=>{writes+=1;}};
|
||||
const workflow=createWorkflow({controller,qs:selector=>elements.get(selector),getLogin:()=> 'timmy',
|
||||
getItem:id=>id.includes(':42:')?{kind:'issue',title:'Ship mobile overview',repository:'stackchain/dashboard',number:42}:null,
|
||||
openPlanner:()=>{opened+=1;},setReviewMode:value=>{reviewMode=value;},escapeHtml:value=>value,escapeAttribute:value=>value,
|
||||
todayWork:{replace:()=>{},replacePlanning:()=>{}},refresh:()=>{},warm:()=>{}});
|
||||
await workflow.open({disabled:false});
|
||||
console.log(JSON.stringify({reviewing:workflow.reviewing(),reviewMode,writes,opened,copy:workflow.copy(),
|
||||
reviewHidden:elements.get('#week-review').hidden,datesHidden:elements.get('#week-plan-dates').hidden,
|
||||
markup:reviewDays.innerHTML,status:elements.get('#week-review-status').textContent,
|
||||
confirmHidden:elements.get('#confirm-week-plan').hidden,editWeekHidden:elements.get('#edit-week-plan').hidden,
|
||||
editWeekLabel:elements.get('#edit-week-plan').textContent}));
|
||||
""")
|
||||
|
||||
assert result["reviewing"] is True
|
||||
assert result["reviewMode"] is True
|
||||
assert result["writes"] == 0
|
||||
assert result["copy"] == {
|
||||
"title": "Week Ahead", "heading": "Seven-day overview",
|
||||
"available": "Planned work", "build": "Edit week",
|
||||
}
|
||||
assert result["reviewHidden"] is False
|
||||
assert result["datesHidden"] is True
|
||||
assert "Ship mobile overview" in result["markup"]
|
||||
assert "Next up" in result["markup"]
|
||||
assert "data-week-move" not in result["markup"]
|
||||
assert result["status"] == "Week Ahead overview · no changes made."
|
||||
assert result["confirmHidden"] is True
|
||||
assert result["editWeekHidden"] is False
|
||||
assert result["editWeekLabel"] == "Edit week"
|
||||
|
||||
|
||||
def test_week_workflow_opens_review_after_day_seven_and_blocks_duplicate_confirmation():
|
||||
result = run_controller("""
|
||||
const createWorkflow=createWeekPlan.Workflow;
|
||||
@@ -213,7 +271,7 @@ const root=makeElement();
|
||||
Object.defineProperty(root,'innerHTML',{set(value){this.value=value;this.buttons=[];},get(){return this.value||'';}});
|
||||
elements.set('#week-plan-dates',root);
|
||||
for(const selector of ['#mobile-week-summary','#my-work-action-status','#week-plan-progress','#save-today-plan',
|
||||
'#week-review','#week-review-days','#week-review-duplicates','#confirm-week-plan','#week-review-status']) elements.set(selector,makeElement());
|
||||
'#week-review','#week-review-days','#week-review-duplicates','#confirm-week-plan','#week-review-status','#edit-week-plan']) elements.set(selector,makeElement());
|
||||
let reviewMode=false;
|
||||
const review={days:dates.map((date,index)=>({plan_date:date,label:'Day '+(index+1),ids:index<2?['shared']:[],
|
||||
capacity_minutes:index===0?30:60,planned_minutes:index===0?45:15,overloaded:index===0})),
|
||||
@@ -225,6 +283,7 @@ const workflow=createWorkflow({controller,qs:selector=>elements.get(selector),ge
|
||||
openPlanner:()=>{},setReviewMode:value=>{reviewMode=value;},escapeHtml:value=>value,escapeAttribute:value=>value,
|
||||
todayWork:{replace:()=>{},replacePlanning:()=>{}},refresh:()=>{},warm:()=>{}});
|
||||
await workflow.open({disabled:false});
|
||||
workflow.editWeek();
|
||||
for(let index=0;index<6;index++) workflow.advance();
|
||||
const advanced=workflow.advance();
|
||||
console.log(JSON.stringify({advanced,reviewing:workflow.reviewing(),reviewMode,
|
||||
|
||||
Reference in new issue
Block a user