From dbabd8640b52275203eae1ea94575bd0fe11e017 Mon Sep 17 00:00:00 2001 From: timmy Date: Thu, 27 Aug 2026 07:09:06 +0000 Subject: [PATCH] feat: personalize adaptive mobile queue priority (Closes #1460) --- frontend/dashboard.css | 10 ++ frontend/dashboard.js | 20 +++ frontend/index.html | 10 ++ frontend/mobile-queue-launcher.js | 41 +++--- frontend/mobile-queue-priority.js | 123 +++++++++++++++++ frontend/service-worker.js | 1 + src/frontend_bundle.py | 2 +- .../test_adaptive_mobile_queues_release.py | 63 +++++++++ tests/test_mobile_task_dock.py | 129 ++++++++++++++++++ tests/test_service_worker.py | 1 + 10 files changed, 383 insertions(+), 17 deletions(-) create mode 100644 frontend/mobile-queue-priority.js diff --git a/frontend/dashboard.css b/frontend/dashboard.css index 6d2b9d5..90ca0c9 100644 --- a/frontend/dashboard.css +++ b/frontend/dashboard.css @@ -1515,6 +1515,16 @@ textarea { resize: vertical; min-height: 120px; } .mobile-queue-next { display:grid; gap:6px; margin-top:12px; padding:12px; border:1px solid #60a5fa; border-radius:14px; background:#122f50; } .mobile-queue-next p, .mobile-queue-group h3 { margin:0; } .mobile-queue-next button { min-height:48px; width:100%; text-align:center; font-weight:800; } + .mobile-queue-priority { margin-top:12px; border:1px solid #31577f; border-radius:12px; background:#0b1b30; } + .mobile-queue-priority > summary { min-height:44px; display:flex; align-items:center; padding:0 12px; cursor:pointer; font-weight:700; } + .mobile-queue-priority > p { margin:0; padding:0 12px 10px; } + .mobile-queue-priority-list { display:grid; gap:6px; padding:0 8px; } + .mobile-queue-priority-row { display:grid; grid-template-columns:minmax(0,1fr) auto; align-items:center; gap:8px; min-width:0; padding:6px 4px; border-top:1px solid #233f61; } + .mobile-queue-priority-row > span:first-child { min-width:0; overflow-wrap:anywhere; font-weight:700; } + .mobile-queue-priority-controls { display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:4px; } + .mobile-queue-priority-controls button { min-height:44px; min-width:64px; padding:6px 8px; } + .mobile-queue-priority-footer { display:grid; gap:6px; padding:10px 12px 12px; } + .mobile-queue-priority-footer button { min-height:44px; } .mobile-queue-group { margin-top:16px; } .mobile-queue-group h3 { font-size:1rem; } .mobile-queue-all { margin-top:16px; } diff --git a/frontend/dashboard.js b/frontend/dashboard.js index 77b83d7..219844b 100644 --- a/frontend/dashboard.js +++ b/frontend/dashboard.js @@ -114,6 +114,7 @@ let preparationItems = {}; let offlineWorkMode = false; let renderMobileQueuePresentation = () => {}; + let mobileQueuePriority = null; const followingQueue = attachFollowing(item => { searchPreviewReturnKind = 'following'; return searchPreview.open(item); @@ -183,6 +184,7 @@ announce: announceWork, getCounts: () => queueCounts, isOnline: () => !offlineWorkMode, + getRoutineOrder: () => mobileQueuePriority?.getOrder(), getPreparation: () => { const briefing = mobileStartDay.briefing(); return {...briefing, active:mobileStartDay.state().active}; @@ -428,6 +430,20 @@ let planningOwnerLogin = ''; let planningOwnerAccountKey = ''; let activeFlushLogin = ''; + mobileQueuePriority = createMobileQueuePriority({ + storage: localStorage, + getLogin: () => confirmedOwnerLogin, + document, + list: qs('#mobile-queue-priority-list'), + resetButton: qs('#reset-mobile-queue-priority'), + status: qs('#mobile-queue-priority-status'), + labels: { + attention:'Attention', today:'Today', update:'Updates', agenda:'Agenda', + following:'Following', authored:'My PRs', filed:'Filed', later:'Later', draft:'Drafts', + }, + onChange: () => renderMobileQueuePresentation(), + }); + mobileQueuePriority.start(); let rR = null; function rRC() { if (rR) return rR; @@ -5620,6 +5636,8 @@ activeFlushLogin = contextIdentityFresh ? String(snapshot.context.user?.login || '').trim() : ''; if (activeFlushLogin) { confirmedOwnerLogin = activeFlushLogin; + mobileQueuePriority.render(); + renderMobileQueuePresentation(); void refreshPhotoDraftInbox(); timerView.restore(todaySync.flush()); restoreReleaseReceipt(); @@ -7951,6 +7969,8 @@ if (!saved) return false; const outage = mode === 'outage'; confirmedOwnerLogin = String(saved.user?.login || '').trim(); + mobileQueuePriority.render(); + renderMobileQueuePresentation(); restoreReleaseReceipt(); planningOwnerLogin = confirmedOwnerLogin; planningOwnerAccountKey = confirmedOwnerLogin && saved.user?.id ? diff --git a/frontend/index.html b/frontend/index.html index e490046..5b64cb2 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -2183,6 +2183,15 @@

Start / Continue

+
+ Customize routine order +

Delivery and Human Gates always stay first. Move the routine queues to match how you work.

+
+ +