diff options
Diffstat (limited to 'packages')
13 files changed, 69 insertions, 0 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/app.js b/packages/meshbay-hub/src/meshbay_hub/static/app.js index de47982..dfd0aeb 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/app.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/app.js @@ -269,6 +269,20 @@ function TransferRow({ it }) { <${Icon} name=${it.status === 'paused' ? 'play' : 'pause'} /> </button> `} + ${!it.pausable && downloads.SUPPORTED && it.kind === 'download' + && (it.status === 'running' || it.status === 'queued') && html` + ${/* Say why, rather than leaving a gap where a button is on the row + above. Without a granted folder this browser writes through the + service worker — a download it already owns, which cannot be + paused — so the button is absent for a reason nobody can see, + and an upload beside it has one. Shown only where choosing a + folder is actually possible: on Firefox and Safari there is no + folder to choose and this hint would be a lie. */''} + <span class="transfer-nopause" title=${t('transfers.not_pausable')} + aria-label=${t('transfers.not_pausable')}> + <${Icon} name="pause" /> + </span> + `} ${(it.status === 'running' || it.status === 'queued' || it.status === 'preparing' || it.status === 'paused') && html` <button class="transfer-cancel" diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/de.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/de.js index 738b131..0f632e3 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/de.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/de.js @@ -590,6 +590,7 @@ export default { 'transfers.pause': 'Anhalten', 'transfers.resume': 'Fortsetzen', 'transfers.paused': 'Angehalten', + 'transfers.not_pausable': 'Kann nicht angehalten werden — wählen Sie in den Einstellungen einen Download-Ordner', 'transfers.pause_one': '{name} anhalten', 'transfers.resume_one': '{name} fortsetzen', 'transfers.eta_seconds': 'noch {n} s', diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/en.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/en.js index 0b9de8a..cb7f4a0 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/en.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/en.js @@ -706,6 +706,7 @@ export default { 'transfers.pause': 'Pause', 'transfers.resume': 'Resume', 'transfers.paused': 'Paused', + 'transfers.not_pausable': 'Cannot be paused — choose a download folder in Settings to enable it', 'transfers.pause_one': 'Pause {name}', 'transfers.resume_one': 'Resume {name}', 'transfers.eta_seconds': '{n}s left', diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/es.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/es.js index 8da8f9f..fe1c13b 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/es.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/es.js @@ -586,6 +586,7 @@ export default { 'transfers.pause': 'Pausar', 'transfers.resume': 'Reanudar', 'transfers.paused': 'En pausa', + 'transfers.not_pausable': 'No se puede pausar — elija una carpeta de descargas en Ajustes para activarlo', 'transfers.pause_one': 'Pausar {name}', 'transfers.resume_one': 'Reanudar {name}', 'transfers.eta_seconds': 'quedan {n} s', diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/fr.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/fr.js index 3135c03..ea3f60e 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/fr.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/fr.js @@ -589,6 +589,7 @@ export default { 'transfers.pause': 'Suspendre', 'transfers.resume': 'Reprendre', 'transfers.paused': 'En pause', + 'transfers.not_pausable': 'Non suspendable — choisissez un dossier de téléchargement dans les Réglages pour l\'activer', 'transfers.pause_one': 'Suspendre {name}', 'transfers.resume_one': 'Reprendre {name}', 'transfers.eta_seconds': '{n} s restantes', diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/it.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/it.js index 91f0e9b..0687b25 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/it.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/it.js @@ -589,6 +589,7 @@ export default { 'transfers.pause': 'Sospendi', 'transfers.resume': 'Riprendi', 'transfers.paused': 'In pausa', + 'transfers.not_pausable': 'Non si può sospendere — scelga una cartella di download nelle Impostazioni', 'transfers.pause_one': 'Sospendi {name}', 'transfers.resume_one': 'Riprendi {name}', 'transfers.eta_seconds': '{n} s rimanenti', diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/ja.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/ja.js index b352188..a02e058 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/ja.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/ja.js @@ -581,6 +581,7 @@ export default { 'transfers.pause': '一時停止', 'transfers.resume': '再開', 'transfers.paused': '一時停止中', + 'transfers.not_pausable': '一時停止できません。設定でダウンロードフォルダーを選ぶと使えます', 'transfers.pause_one': '{name} を一時停止', 'transfers.resume_one': '{name} を再開', 'transfers.eta_seconds': '残り {n} 秒', diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/nl.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/nl.js index e0a799d..0235d8a 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/nl.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/nl.js @@ -590,6 +590,7 @@ export default { 'transfers.pause': 'Pauzeren', 'transfers.resume': 'Hervatten', 'transfers.paused': 'Gepauzeerd', + 'transfers.not_pausable': 'Kan niet worden gepauzeerd — kies een downloadmap in Instellingen', 'transfers.pause_one': '{name} pauzeren', 'transfers.resume_one': '{name} hervatten', 'transfers.eta_seconds': 'nog {n} s', diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/pl.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/pl.js index e6319b0..af4a5bb 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/pl.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/pl.js @@ -602,6 +602,7 @@ export default { 'transfers.pause': 'Wstrzymaj', 'transfers.resume': 'Wznów', 'transfers.paused': 'Wstrzymano', + 'transfers.not_pausable': 'Nie można wstrzymać — proszę wybrać folder pobierania w Ustawieniach', 'transfers.pause_one': 'Wstrzymaj {name}', 'transfers.resume_one': 'Wznów {name}', 'transfers.eta_seconds': 'pozostało {n} s', diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/pt-BR.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/pt-BR.js index 02c8356..f179c6f 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/pt-BR.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/pt-BR.js @@ -588,6 +588,7 @@ export default { 'transfers.pause': 'Pausar', 'transfers.resume': 'Retomar', 'transfers.paused': 'Pausado', + 'transfers.not_pausable': 'Não pode ser pausado — escolha uma pasta de downloads em Configurações', 'transfers.pause_one': 'Pausar {name}', 'transfers.resume_one': 'Retomar {name}', 'transfers.eta_seconds': 'faltam {n} s', diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js index 6c4c73f..c89bbdc 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js @@ -569,6 +569,7 @@ export default { 'transfers.pause': '暂停', 'transfers.resume': '继续', 'transfers.paused': '已暂停', + 'transfers.not_pausable': '无法暂停——请在设置中选择下载文件夹以启用', 'transfers.pause_one': '暂停 {name}', 'transfers.resume_one': '继续 {name}', 'transfers.eta_seconds': '剩余 {n} 秒', diff --git a/packages/meshbay-hub/src/meshbay_hub/static/style.css b/packages/meshbay-hub/src/meshbay_hub/static/style.css index a37e541..5e08a6a 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/style.css +++ b/packages/meshbay-hub/src/meshbay_hub/static/style.css @@ -1986,6 +1986,16 @@ a.transfer-name { display: flex; } .transfer-pause:hover { color: var(--accent); } +/* Not a button: there is nothing to click. Dimmer than the cancel beside it, + and it carries its explanation in a tooltip rather than in the row, which + would be four lines of prose in a panel that has none. */ +.transfer-nopause { + color: var(--text-dim); + opacity: .45; + padding: 0 2px; + display: flex; + cursor: help; +} /* A paused bar keeps its fill -- what was written is still on disk -- but stops looking like something in progress. */ .dl-fill.dl-paused { background: var(--text-dim); } diff --git a/packages/meshbay-hub/tests/test_transfers.py b/packages/meshbay-hub/tests/test_transfers.py index d19a458..d93cf80 100644 --- a/packages/meshbay-hub/tests/test_transfers.py +++ b/packages/meshbay-hub/tests/test_transfers.py @@ -879,3 +879,38 @@ console.log(JSON.stringify({ active })); proc = subprocess.run(["node", str(script)], capture_output=True, text=True) assert proc.returncode == 0, proc.stderr assert json.loads(proc.stdout)["active"] == 1 + + +def test_a_row_that_cannot_pause_says_so_where_the_button_would_be(): + """Reported from Chrome: four downloads with no pause button and an upload + with one, and no way to tell why. + + The reason is real — without a granted folder the browser writes through the + service worker, a download it already owns and cannot pause — but it was + stated only in a Settings line nobody reads on the way to a download. A gap + where the row above has a button is not an explanation. + + Shown only where a folder can actually be chosen: Firefox and Safari have + none to choose, and "choose a folder" would be advice that cannot be taken. + """ + src = (STATIC / "app.js").read_text() + row = src[src.index("function TransferRow"):] + row = row[:row.index("\n}\n")] + + hint = row[row.index("!it.pausable"):] + hint = hint[:hint.index("`}")] + assert "downloads.SUPPORTED" in hint, ( + "the hint would tell a Firefox user to choose a folder it cannot offer") + assert "it.kind === 'download'" in hint, ( + "an upload is always pausable; this is about download targets") + assert "transfers.not_pausable" in hint, "the reason is not stated" + # Not a button. There is nothing to click, and a disabled one invites the + # click anyway. + assert "<button" not in hint + + +def test_the_reason_is_translated_everywhere(): + """`t()` falls back to the key, so a missing catalogue entry shows + `transfers.not_pausable` in a tooltip rather than a sentence.""" + for path in sorted((STATIC / "locales").glob("*.js")): + assert "'transfers.not_pausable'" in path.read_text(), path.name |