From 218dd4376492a0897c2fded7831293f92bd00f28 Mon Sep 17 00:00:00 2001 From: timmy Date: Fri, 21 Aug 2026 07:29:23 +0000 Subject: [PATCH] feat: update repeated Week Ahead calendar exports (Closes #1214) --- frontend/week-calendar.js | 2 +- tests/test_week_calendar.py | 29 ++++++++++++++++++++++++++++- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/frontend/week-calendar.js b/frontend/week-calendar.js index e06955c..a14a6c4 100644 --- a/frontend/week-calendar.js +++ b/frontend/week-calendar.js @@ -52,7 +52,7 @@ const lines=['BEGIN:VCALENDAR','VERSION:2.0','PRODID:-//Stackchain//Week Ahead//EN','CALSCALE:GREGORIAN','METHOD:PUBLISH','X-WR-CALNAME:Stackchain Week Ahead',`X-WR-TIMEZONE:${timezone}`,'BEGIN:VTIMEZONE',`TZID:${timezone}`,'END:VTIMEZONE']; (blocks||[]).forEach(block=>{ const day=compact(block.plan_date),reference=block.repository+(block.number!=null?' #'+block.number:''); - lines.push('BEGIN:VEVENT',`UID:week-${revision}-${day}-${stableId(block.id)}@stackchain`,`DTSTAMP:${stamp}`, + lines.push('BEGIN:VEVENT',`UID:week-${stableId(block.id)}@stackchain`,`SEQUENCE:${Math.max(0,Math.floor(Number(revision)||0))}`,`DTSTAMP:${stamp}`, `DTSTART;TZID=${timezone}:${day}T${compact(block.start_time)}00`,`DTEND;TZID=${timezone}:${day}T${compact(block.end_time)}00`, `SUMMARY:${escapeText(block.title||'Untitled work')}`,`DESCRIPTION:${escapeText(reference+' ยท Stackchain Week Ahead')}`, `URL:${String(block.url||'')}`,'TRANSP:OPAQUE','END:VEVENT'); diff --git a/tests/test_week_calendar.py b/tests/test_week_calendar.py index c76c9cf..5932888 100644 --- a/tests/test_week_calendar.py +++ b/tests/test_week_calendar.py @@ -63,12 +63,39 @@ console.log(JSON.stringify({{blocks,text}})); assert "DTSTART;TZID=America/New_York:20260821T094500" in text assert "DTEND;TZID=America/New_York:20260821T101500" in text assert "TRANSP:OPAQUE" in text - assert "UID:week-7-20260821-issue-stackchain-dashboard-12@stackchain" in text + assert "UID:week-issue-stackchain-dashboard-12@stackchain" in text + assert "SEQUENCE:7" in text assert "SUMMARY:Plan\\, ship\\; verify" in text unfolded = text.replace("\r\n ", "") assert "URL:https://forge.alexanderwhitestone.com/git/stackchain/stackchain-dashboard/issues/12" in unfolded +def test_week_calendar_reexports_update_stable_distinct_work_events(): + source = f""" +const calendar=require({json.dumps(str(WEEK_CALENDAR))}); +const issue={{id:'issue:stackchain/dashboard:12:',title:'Ship it',repository:'stackchain/dashboard',number:12, + plan_date:'2026-08-21',start_time:'09:00',end_time:'09:30'}}; +const moved={{...issue,plan_date:'2026-08-22',start_time:'14:00',end_time:'14:30'}}; +const pull={{...moved,id:'pull:stackchain/dashboard:12:'}}; +const first=calendar.serializeWeekCalendar([issue],{{timezone:'UTC',revision:7,generatedAt:'20260820T120000Z'}}); +const second=calendar.serializeWeekCalendar([moved,pull],{{timezone:'UTC',revision:8,generatedAt:'20260821T120000Z'}}); +const events=text=>text.split('BEGIN:VEVENT').slice(1).map(value=>({{ + uid:value.match(/UID:([^\\r]+)/)[1],sequence:Number(value.match(/SEQUENCE:(\\d+)/)[1]) +}})); +console.log(JSON.stringify({{first:events(first),second:events(second)}})); +""" + + result = run_node(source) + assert result["first"] == [{ + "uid": "week-issue-stackchain-dashboard-12@stackchain", + "sequence": 7, + }] + assert result["second"] == [ + {"uid": "week-issue-stackchain-dashboard-12@stackchain", "sequence": 8}, + {"uid": "week-pull-stackchain-dashboard-12@stackchain", "sequence": 8}, + ] + + def test_week_calendar_places_whole_tasks_in_imported_free_windows_and_reports_unfitted_work(): source = f""" const calendar=require({json.dumps(str(WEEK_CALENDAR))}); -- 2.43.0