aboutsummaryrefslogtreecommitdiffstats
path: root/packages
diff options
context:
space:
mode:
Diffstat (limited to 'packages')
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/app.js14
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/de.js1
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/en.js1
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/es.js1
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/fr.js1
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/it.js1
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/ja.js1
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/nl.js1
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/pl.js1
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/pt-BR.js1
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js1
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/style.css10
-rw-r--r--packages/meshbay-hub/tests/test_transfers.py35
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