From 78839a50fef618b5302b6fd0927b26c1dff50643 Mon Sep 17 00:00:00 2001 From: timmy Date: Thu, 20 Aug 2026 22:01:58 +0000 Subject: [PATCH] feat: batch-plan Search results into Week Ahead (Closes #1196) --- README.md | 5 + frontend/dashboard.css | 7 + frontend/dashboard.js | 2 +- frontend/index.html | 11 ++ frontend/search-batch-plan.js | 170 +++++++++++++++++++++- src/frontend_bundle.py | 4 +- tests/e2e/test_mobile_search_week_plan.py | 34 +++++ tests/test_search_batch_plan.py | 77 ++++++++++ 8 files changed, 305 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index c09717d..83b7204 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,11 @@ over-capacity admission requires a second confirmation. The action claims unassi checks, stages the canonical issue through the account-bound Week Ahead outbox, and preserves the Search preview through cancel or browser Back. Offline saves report **sync pending**; if assignment succeeds but local planning fails, the dashboard reports **Assigned, not planned** and leaves the issue recoverable in My Work. +Search selection mode extends that flow across several open issues with **Plan Week Ahead**. One phone-safe +review assigns each issue a future day and estimate, validates five-item limits and daily capacity before any +claim, and requires a second confirmation for overload. Confirmed rows are staged into one canonical Week +Ahead update and flushed together; partial assignment or offline sync is reported without discarding the +selection, so claimed work remains recoverable from My Work. Commentable mobile Search previews support camera capture and gallery selection for up to five ordered photos, including captions, crop/annotation/redaction review, and metadata-stripping re-encoding. Operators can queue photo-only, text-only, or mixed replies without leaving their Search pass, including while offline. diff --git a/frontend/dashboard.css b/frontend/dashboard.css index a8201c8..6a0d6b7 100644 --- a/frontend/dashboard.css +++ b/frontend/dashboard.css @@ -212,6 +212,13 @@ textarea { resize: vertical; min-height: 120px; } .search-batch-estimate-review input { min-height:44px; width:76px; } .search-batch-estimate-actions { position:sticky; bottom:0; display:grid; grid-template-columns:1fr 1fr; gap:8px; padding-bottom:env(safe-area-inset-bottom); background:#101f36; } .search-batch-estimate-actions button { min-height:44px; } +.search-week-batch-review { display:grid; gap:12px; max-height:calc(100dvh - 48px); overflow:auto; overflow-x:hidden; padding:12px; border:1px solid #2a496e; border-radius:12px; background:#101f36; } +.search-week-batch-review[hidden] { display:none; } +.search-week-batch-review > div:first-child, #search-week-batch-list { display:grid; gap:10px; } +.search-week-batch-row { display:grid; gap:8px; padding:10px 0; border-bottom:1px solid #2a496e; overflow-wrap:anywhere; } +.search-week-batch-row-controls { display:grid; grid-template-columns:minmax(0,1fr) minmax(96px,.45fr); gap:8px; } +.search-week-batch-row select, .search-week-batch-row input, .search-week-batch-actions button { min-height:44px; width:100%; } +.search-week-batch-actions { position:sticky; bottom:0; display:grid; grid-template-columns:1fr 1fr; gap:8px; padding-bottom:env(safe-area-inset-bottom); background:#101f36; } .search-release-review { display:grid; gap:12px; max-height:calc(100dvh - 48px); overflow:auto; padding:12px; border:1px solid #2a496e; border-radius:12px; background:#101f36; overflow-wrap:anywhere; } .search-release-review[hidden] { display:none; } .search-release-review > div:first-child, #search-release-list, .search-release-row { display:grid; gap:6px; } diff --git a/frontend/dashboard.js b/frontend/dashboard.js index 404417e..47f4598 100644 --- a/frontend/dashboard.js +++ b/frontend/dashboard.js @@ -5750,7 +5750,7 @@ searchBatchPlanning = mountSearchBatchPlanning( document, createBatchFindWork, todayWork, ()=>planningOwnerLogin, fetchReviewJson, searchPreviewPath, queueToday, todaySync, acceptClaimedIssue, i=>commandItems[i]?.result, - ()=>renderCommands(qs('#cmd-input').value), escapeHtml, escAttr, laterWork, laterPicker + ()=>renderCommands(qs('#cmd-input').value), escapeHtml, escAttr, laterWork, laterPicker, weekPlan, localStorage ); searchDefer = createSearchDefer({ claim: detail => searchPreview.claim(detail), diff --git a/frontend/index.html b/frontend/index.html index 951eeb1..9e9e7d4 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -738,6 +738,7 @@ No issues selected. + @@ -751,6 +752,16 @@ +