From a25b547d20b5754d7cb6d51fe24c37680cd29620 Mon Sep 17 00:00:00 2001 From: timmy Date: Fri, 7 Aug 2026 20:26:14 +0000 Subject: [PATCH] fix: scope mobile share install to dashboard path (#223) --- frontend/index.html | 2 +- frontend/manifest.webmanifest | 12 ++++++------ frontend/service-worker.js | 7 ++++++- tests/test_my_work.py | 2 +- tests/test_work_pages.py | 8 ++++++-- 5 files changed, 20 insertions(+), 11 deletions(-) diff --git a/frontend/index.html b/frontend/index.html index be6676e..5adb840 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -3067,7 +3067,7 @@ textarea { resize: vertical; min-height: 120px; } if (workSession.active()) workSession.reconcile(); }); if ('serviceWorker' in navigator) { - navigator.serviceWorker.register('/service-worker.js').catch(error => + navigator.serviceWorker.register('service-worker.js').catch(error => console.warn('Stackchain install support unavailable', error) ); } diff --git a/frontend/manifest.webmanifest b/frontend/manifest.webmanifest index d9f4c9d..8e0f8db 100644 --- a/frontend/manifest.webmanifest +++ b/frontend/manifest.webmanifest @@ -2,18 +2,18 @@ "name": "Stackchain Dashboard", "short_name": "Stackchain", "description": "Capture, plan, and complete Gitea work from mobile.", - "id": "/", - "start_url": "/", - "scope": "/", + "id": "./", + "start_url": "./", + "scope": "./", "display": "standalone", "background_color": "#07111f", "theme_color": "#0b1220", "icons": [ - {"src": "/static/icons/stackchain-192.png", "sizes": "192x192", "type": "image/png"}, - {"src": "/static/icons/stackchain-512.png", "sizes": "512x512", "type": "image/png"} + {"src": "static/icons/stackchain-192.png", "sizes": "192x192", "type": "image/png"}, + {"src": "static/icons/stackchain-512.png", "sizes": "512x512", "type": "image/png"} ], "share_target": { - "action": "/", + "action": "./", "method": "GET", "enctype": "application/x-www-form-urlencoded", "params": {"title": "title", "text": "text", "url": "url"} diff --git a/frontend/service-worker.js b/frontend/service-worker.js index 1d66c5d..f4bff97 100644 --- a/frontend/service-worker.js +++ b/frontend/service-worker.js @@ -1,5 +1,10 @@ const CACHE = 'stackchain-shell-v1'; -const SHELL = ['/manifest.webmanifest', '/static/icons/stackchain-192.png', '/static/icons/stackchain-512.png']; +const BASE = new URL('./', self.location.href).pathname; +const SHELL = [ + BASE + 'manifest.webmanifest', + BASE + 'static/icons/stackchain-192.png', + BASE + 'static/icons/stackchain-512.png', +]; self.addEventListener('install', event => { event.waitUntil(caches.open(CACHE).then(cache => cache.addAll(SHELL)).then(() => self.skipWaiting())); diff --git a/tests/test_my_work.py b/tests/test_my_work.py index 784e090..3972a08 100644 --- a/tests/test_my_work.py +++ b/tests/test_my_work.py @@ -545,7 +545,7 @@ async def test_dashboard_launches_share_capture_with_draft_conflict_choices(): assert 'id="shared-content-conflict"' in html assert '.shared-content-actions button { min-height:44px;' in html assert "history.replaceState({}, '', cleanUrl)" in html - assert "navigator.serviceWorker.register('/service-worker.js')" in html + assert "navigator.serviceWorker.register('service-worker.js')" in html @pytest.mark.anyio diff --git a/tests/test_work_pages.py b/tests/test_work_pages.py index ae949f9..033676c 100644 --- a/tests/test_work_pages.py +++ b/tests/test_work_pages.py @@ -73,12 +73,16 @@ async def test_pwa_assets_expose_root_scoped_share_target_without_caching_api_da assert manifest.status_code == 200 assert manifest.headers["content-type"].startswith("application/manifest+json") + assert manifest.json()["id"] == "./" + assert manifest.json()["start_url"] == "./" + assert manifest.json()["scope"] == "./" assert manifest.json()["share_target"] == { - "action": "/", "method": "GET", "enctype": "application/x-www-form-urlencoded", + "action": "./", "method": "GET", "enctype": "application/x-www-form-urlencoded", "params": {"title": "title", "text": "text", "url": "url"}, } assert worker.status_code == 200 assert worker.headers["content-type"].startswith("application/javascript") assert worker.headers["service-worker-allowed"] == "/" assert "request.url.includes('/api/')" in worker.text - assert "request.method !== 'GET'" in worker.text \ No newline at end of file + assert "request.method !== 'GET'" in worker.text + assert "new URL('./', self.location.href).pathname" in worker.text \ No newline at end of file